package generate;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class BankGenerator {
	
	public static void main(String[] args) {
		
		String bankKeyInHex = "9F7E3D9AB71D3F127E041ACF4355F962";
		String ivInHex = "683C4FCA500A1978A1A7983A0728A664";
		
		PrintWriter outputFile = null;
		Scanner scan = null;
		
		// Initialize bank's key
        Key bankKey = new SecretKeySpec(hexStringToByteArray(bankKeyInHex), "AES");
        
        // Initialize bank's IV
        IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray(ivInHex));
        
        // Initialize cipher
        Cipher ciph = null;
        try {
			ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
			ciph.init(Cipher.ENCRYPT_MODE, bankKey, iv);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		}
		
        // Write userinfo.txt
		try {
			outputFile = new PrintWriter(new File("userinfo.txt"));
			
			// Put in Alice's info
			scan = new Scanner(new File("Alice.card"));
			String aliceInfo = "Alice";
			
			while (scan.hasNext()) {
				aliceInfo += "\t" + scan.next();
			}
			
			// Encode Alice Info
			String encMsgInHex = "";
			byte[] aliceInfoInBytes = null;
			
			System.out.println(aliceInfo);
			
			try {
				aliceInfoInBytes = ciph.doFinal(aliceInfo.getBytes("US-ASCII"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			
			for (int i = 0; i < aliceInfoInBytes.length; i++) {
				encMsgInHex += String.format("%02X", aliceInfoInBytes[i]);
			}
			
			outputFile.println(encMsgInHex);
			
			// Put in Bob's info
			scan = new Scanner(new File("Bob.card"));
			String bobInfo = "Bob";
			
			while (scan.hasNext()) {
				bobInfo += "\t" + scan.next();
			}
			
			System.out.println(bobInfo);
			
			// Encode Bob Info
			encMsgInHex = "";
			byte[] bobInfoInBytes = null;
			
			try {
				bobInfoInBytes = ciph.doFinal(bobInfo.getBytes("US-ASCII"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			
			for (int i = 0; i < bobInfoInBytes.length; i++) {
				encMsgInHex += String.format("%02X", bobInfoInBytes[i]);
			}
			
			outputFile.println(encMsgInHex);
			
			// Put in Carol's info
			scan = new Scanner(new File("Carol.card"));
			String carolInfo = "Carol";
			
			while (scan.hasNext()) {
				carolInfo += "\t" + scan.next();
			}
			
			System.out.println(carolInfo);
			
			// Encode Carol Info
			encMsgInHex = "";
			byte[] carolInfoInBytes = null;
			
			try {
				carolInfoInBytes = ciph.doFinal(carolInfo.getBytes("US-ASCII"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			
			for (int i = 0; i < carolInfoInBytes.length; i++) {
				encMsgInHex += String.format("%02X", carolInfoInBytes[i]);
			}
			
			outputFile.println(encMsgInHex);
			
			outputFile.flush();
			outputFile.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		String msg;
		
		System.out.println();
		
		// Write balance.txt
		try {
			outputFile = new PrintWriter(new File("balance.txt"));
			
			// Fill out information for Carol
			scan = new Scanner(new File("CarolPIN.txt"));
			
			int carolPIN = scan.nextInt();
			
			scan = new Scanner(new File("Carol.card"));
			
			// Initialize carol's key
	        Key carolKey = new SecretKeySpec(hexStringToByteArray(scan.next()), "AES");
	        
	        // Initialize carol's IV
	        IvParameterSpec carolIv = new IvParameterSpec(hexStringToByteArray(scan.next()));
			
			try {
				ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
				ciph.init(Cipher.ENCRYPT_MODE, carolKey, carolIv);
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			}
			
			msg = carolPIN + "\t0";
			
			System.out.println(msg);
			
			String encMsgInHex = "";
			byte[] carolInfoInBytes = null;
			
			try {
				carolInfoInBytes = ciph.doFinal(msg.getBytes("US-ASCII"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			
			for (int i = 0; i < carolInfoInBytes.length; i++) {
				encMsgInHex += String.format("%02X", carolInfoInBytes[i]);
			}
			
			outputFile.println(encMsgInHex);
			
			// Fill out information for Alice
			scan = new Scanner(new File("AlicePIN.txt"));
			
			int alicePIN = scan.nextInt();
			
			scan = new Scanner(new File("Alice.card"));
			
			// Initialize alice's key
	        Key aliceKey = new SecretKeySpec(hexStringToByteArray(scan.next()), "AES");
	        
	        // Initialize alice's IV
	        IvParameterSpec aliceIv = new IvParameterSpec(hexStringToByteArray(scan.next()));
			
			try {
				ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
				ciph.init(Cipher.ENCRYPT_MODE, aliceKey, aliceIv);
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			}
			
			msg = alicePIN + "\t100";
			
			System.out.println(msg);
			
			encMsgInHex = "";
			byte[] aliceInfoInBytes = null;
			
			try {
				aliceInfoInBytes = ciph.doFinal(msg.getBytes("US-ASCII"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			
			for (int i = 0; i < aliceInfoInBytes.length; i++) {
				encMsgInHex += String.format("%02X", aliceInfoInBytes[i]);
			}
			
			outputFile.println(encMsgInHex);
			
			// Fill out information for Bob
			scan = new Scanner(new File("BobPIN.txt"));
			
			int bobPIN = scan.nextInt();
			
			scan = new Scanner(new File("Bob.card"));
			
			// Initialize bob's key
	        Key bobKey = new SecretKeySpec(hexStringToByteArray(scan.next()), "AES");
	        
	        // Initialize bob's IV
	        IvParameterSpec bobIv = new IvParameterSpec(hexStringToByteArray(scan.next()));
			
			try {
				ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
				ciph.init(Cipher.ENCRYPT_MODE, bobKey, bobIv);
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				e.printStackTrace();
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			}
			
			msg = bobPIN + "\t100";
			
			System.out.println(msg);
			
			encMsgInHex = "";
			byte[] bobInfoInBytes = null;
			
			try {
				bobInfoInBytes = ciph.doFinal(msg.getBytes("US-ASCII"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				e.printStackTrace();
			} catch (BadPaddingException e) {
				e.printStackTrace();
			}
			
			for (int i = 0; i < bobInfoInBytes.length; i++) {
				encMsgInHex += String.format("%02X", bobInfoInBytes[i]);
			}
			
			outputFile.println(encMsgInHex);
			
			outputFile.flush();
			outputFile.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
        
	}
	
	private static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
					+ Character.digit(s.charAt(i+1), 16));
		}
		return data;
	}

}
